﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace CoffeePotServer
{
    /// <summary>
    /// File: ClientMessage.cs
    /// Author: James Dibble 10009689
    /// Last Revision: 17/03/12
    /// SVN Address:
    /// http://code.google.com/p/cnos-coffeepot-server/source/browse/branches/DibbleBranch/CoffeePotServerLib/CoffeePotServerLib/ClientMessage.cs
    /// </summary>
    class ClientMessage
    {
        #region Attributes
        private List<Addition> _additions = null;
        private int _potRequested;
        private Methods _method;
        private String _message;
        private Safe _safe;
        #endregion

        #region Constructors
        /// <summary>
        /// Create an object representing a message that is recieved from the client.
        /// </summary>
        public ClientMessage() { }

        /// <summary>
        /// Create an object representing a message that is recieved from the client.
        /// </summary>
        /// <param name="message">The message</param>
        public ClientMessage(String message)
        {
            _message = message;
        }
        #endregion

        #region Properties
        /// <summary>
        /// The string sent from the client;
        /// </summary>
        public String Message
        {
            get { return _message; }
            set { _message = value; }
        }

        /// <summary>
        /// The method used by this message.
        /// </summary>
        public Methods Method
        {
            get { return _method; }
        }

        /// <summary>
        /// The pot that was requested by this message.
        /// </summary>
        public int PotRequested
        {
            get { return _potRequested; }
        }

        /// <summary>
        /// The additions that the client requested.
        /// </summary>
        public List<Addition> Additions
        {
            get { return _additions; }
        }

        /// <summary>
        /// The message safe header.
        /// </summary>
        public Safe IsSafe
        {
            get { return _safe; }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Parse the message defined by 'Message' property.
        /// </summary>
        /// <returns>A segmented structure of the message.</returns>
        public ClientMessage ParseMessage()
        {
            //Split the message to take each line seperatly.
            String[] strLinesArr = Regex.Split(_message, "\r\n", RegexOptions.Multiline);
            int intLineCount = 0;
            foreach (String strLine in strLinesArr)
            {
                //Split this line by space character.
                String[] strThisLineArr = strLine.Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (intLineCount == 0)
                {
                    if (strThisLineArr.Length == 3)
                    {
                        GetMessageMethod(strThisLineArr[0]);
                        
                        //Use default pot.
                        if (strThisLineArr[1] == "/") _potRequested = 1;
                        else if (Regex.IsMatch(strThisLineArr[1], "pot-([0-9]+)"))
                        {
                            _potRequested = Convert.ToInt32(strThisLineArr[1].Substring(5));
                        }
                        else throw new ClientResponseException("Invalid Pot",
                                                               ClientResponseException.ExceptionType.INVALIDPOT);

                        if (strThisLineArr[2] != "HTCPCP/1.0") throw new ClientResponseException("Invalid Protocall",
                                                                                                 ClientResponseException.ExceptionType.INVALIDPROTOCALL);
                    }
                    else throw new ClientResponseException("Invalid Request",
                                                           ClientResponseException.ExceptionType.INVALIDREQUEST);
                }
                else if (strThisLineArr.Length > 0)
                {
                    switch (strThisLineArr[0].ToLower())
                    {
                        case "safe:":
                            if (strThisLineArr[1].ToLower() == "yes") _safe = Safe.YES;
                            else if (strThisLineArr[1].ToLower() == "no") _safe = Safe.NO;
                            else throw new ClientResponseException("Invalid Request",
                                                           ClientResponseException.ExceptionType.INVALIDREQUEST);
                            break;
                        case "accept-additions:":
                            this._additions = new List<Addition>();
                            for (int intCount = 1; intCount < strThisLineArr.Length; intCount++)
                            {
                                this._additions.Add(new Addition(strThisLineArr[intCount]));
                            }
                            break;
                    }
                }
                else if (strLine == ""){} //Ignore empty line.
                else throw new ClientResponseException("Invalid Request", ClientResponseException.ExceptionType.INVALIDREQUEST);
                intLineCount++;
            }
            return this;
        }

        /// <summary>
        /// Determine the method the client has requested in this message
        /// </summary>
        /// <param name="methodText">The first section of the top line of the header.</param>
        /// <returns>The method requested by the message.</returns>
        private Methods GetMessageMethod(String methodText)
        {
            switch (methodText.ToUpper())
            {
                case "GET":
                    return Methods.GET;
                case "POST":
                    return Methods.POST;
                case "BREW":
                    return Methods.BREW;
                case "WHEN":
                    return Methods.WHEN;
                case "PROPFIND":
                    return Methods.PROPFIND;
                default:
                    throw new ClientResponseException("Invalid Method",
                                                              ClientResponseException.ExceptionType.INVALIDMETHOD);
            }
        }

        /// <summary>
        /// Get the addition requested from this Accept-additions header feild.
        /// </summary>
        /// <param name="strAddition"></param>
        private void ParseAddition(String strAddition)
        {
            if (_additions == null) _additions = new List<Addition>();
            String[] strAdditionArr = strAddition.Split(';');
            foreach (String strAdd in strAdditionArr)
            {
                _additions.Add(new Addition(strAdd));
            }
        }
        #endregion

        #region Enums
        public enum Methods
        {
            BREW,
            POST,
            GET,
            WHEN,
            PROPFIND,
            NOTSET
        }

        public enum Safe
        {
            YES,
            NO
        }
        #endregion
    }
}